package sicnu.cs.ich.token.security.config;

import lombok.Data;
import org.springframework.util.AntPathMatcher;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * @author CaiKe
 * @date 2021/12/25 15:45
 */
@Deprecated
public class TokenSecurityDEPRECATED {

    /**
     * 不需要权限验证的接口
     */
    private Set<String> authorities;
    /**
     * 匹配器
     */
    private final AntPathMatcher MATCHER;
    /**
     * 公共接口的URI
     */
    private final List<String> AUTH_URIS;
    private final List<String> DENY_URIS;
    private List<String> CHECKED_URIS;
    /**
     * 权限链
     */
    private final List<AuthPair> AUTH_PAIRS;
    /**
     * 其他接口
     *
     * @param MATCHER
     */
    private boolean passOthers = false;
    /**
     * 是否可信
     *
     * @param MATCHER
     */
    private boolean credible = false;

    public TokenSecurityDEPRECATED(AntPathMatcher MATCHER) {
        this.CHECKED_URIS = new ArrayList<>();
        this.DENY_URIS = new ArrayList<>();
        this.AUTH_URIS = new ArrayList<>();
        this.AUTH_PAIRS = new ArrayList<>();
        this.MATCHER = MATCHER;
    }

    /**
     * 设置当前对象的权限
     *
     * @param auths
     */
    public void setAuth(Set<String> auths) {
        authorities = auths;
    }

    /**
     * 标记当前为可信对象（成功解析Token）
     */
    public void assignCredible() {
        credible = true;
    }

    /**
     * 检查当前具有的权限是否满足
     *
     * @param path 路径
     */
    public boolean checkAuth(String path) {
        // 检查“permitAll”类型
        for (String urIs : AUTH_URIS) {
            if (MATCHER.matchStart(urIs, path)) return true;
        }
        // 非可信对象，直接拒绝
        if (!credible) return false;

        // 检查“denyAll”类型
        for (String uris : DENY_URIS) {
            if (MATCHER.matchStart(uris, path)) return false;
        }

        if (!authorities.isEmpty()) {
            // 检查其他类型
            for (AuthPair authPair : AUTH_PAIRS) {
                for (String auth : authPair.getRequiredAuth()) {
                    if (authorities.contains(auth)) {
                        // 如果authority与当前AuthPair相符
                        for (String pattern : authPair.getPatterns()) {
                            if (MATCHER.matchStart(pattern, path))
                                // 如果Path与当前AuthPair相符
                                return makeDecision(authPair, path);
                        }
                    }
                }
            }
        }
        // check others paths

        return passOthers;
    }

    /**
     * 决策是否放行
     *
     * @param authPair
     * @param path
     * @return
     */
    private boolean makeDecision(AuthPair authPair, String path) {
        final int mode = authPair.getAuthMode();
        final String[] auths = authPair.getRequiredAuth();
        if (mode == 1) {
            // hasAny Type
            for (String auth : auths)
                if (authorities.contains(auth)) return true;
        } else if (mode == 2) {
            // hasAll Type
            return authorities.containsAll(Arrays.asList(auths));
        }
        return false;
    }

    /**
     * 初始化当前Token中的一个节点
     *
     * @param patterns
     * @return
     */
    public AuthPair authenticate(String... patterns) {
        return new AuthPair(this, patterns);
    }

    /**
     * 添加公共URI
     *
     * @param patterns
     */
    private void addAuthURIs(String... patterns) {
        AUTH_URIS.addAll(Arrays.asList(patterns));
    }


    private void addDenyURIs(String[] patterns) {
        DENY_URIS.addAll(Arrays.asList(patterns));
    }

    /**
     * 添加权限链
     *
     * @param authPair
     */
    private void addAuthPair(AuthPair authPair) {
        AUTH_PAIRS.add(authPair);
    }

    // Paths not in record
    private void permitOthers() {
        this.CHECKED_URIS = AUTH_PAIRS.stream()
                .map(AuthPair::getPatterns)
                .collect(ArrayList::new, (o, n) -> o.addAll(Arrays.asList(n)), ArrayList::addAll);
        passOthers = true;
    }

    private void denyOthers() {
        passOthers = false;
    }


    @Data
    public static class AuthPair {
        private String[] patterns;
        private String[] requiredAuth;
        /**
         * 校验类型  1-HasAny 2-HasAll
         */
        private int authMode;
        private TokenSecurityDEPRECATED parent;

        public AuthPair(TokenSecurityDEPRECATED tokenSecurity, String... patterns) {
            this.patterns = patterns;
            this.parent = tokenSecurity;
        }


        public TokenSecurityDEPRECATED permitAll() {
            parent.addAuthURIs(patterns);
            return this.parent;
        }

        public TokenSecurityDEPRECATED denyAll() {
            parent.addDenyURIs(patterns);
            return this.parent;
        }

        public TokenSecurityDEPRECATED hasAny(String... auths) {
            this.requiredAuth = auths;
            return addAuthPair(1);
        }

        public TokenSecurityDEPRECATED hasAll(String... auth) {
            return addAuthPair(2);
        }

        private TokenSecurityDEPRECATED addAuthPair(Integer authMode) {
            this.authMode = authMode;
            this.parent.addAuthPair(this);
            return parent;
        }
    }


}